#include <stdio.h>
#include <stdlib.h>
#include <sobjc-commons/defines.h>
#include <sobjc-commons/str_stream.h>
#include <sobjc-commons/str_list.h>
#include <sobjc-commons/utils.h>
#include "command.h"
#include "node.h"
#include "parse.h"
#include "scope.h"
#include "context.h"

#define DEFAULT_RECV_CACHE_VAR      "__objc_recv"

#define SET_SUB(node,mem,sub) \
  do {                           \
    if (sub != NULL)             \
      sub->parent = node;        \
    node->a.mem = sub;           \
  } while (0)

objc_node_t
objc_make_node(int type)
{
  objc_node_t node;

  node = ALLOC(struct objc_node);
  node->type = type;
  node->parent = NULL;
  node->scope = NULL;
  node->lc = 0;
  objc_recorded_line_mark = NULL;

  return node;
}

objc_node_t
objc_make_list_node(int type, objc_node_t sub, ...)
{
  va_list ap;
  objc_node_t node;

  va_start(ap, sub);
  node = objc_make_list_nodev(type, sub, ap);
  va_end(ap);

  return node;
}

objc_node_t
objc_make_list_nodev(int type, objc_node_t sub, va_list ap)
{
  objc_node_t node;
  va_list count;
  int i, size = 0;

  if (sub)
    size++;

  VA_COPY(count, ap);
  while (va_arg(count, objc_node_t) != NULL)
    size++;

  node = objc_make_node(type);
  node->a.l.nsubs = size;
  node->a.l.subs = ALLOC_N(objc_node_t, size);
  if (sub)
    SET_SUB(node, l.subs[0], sub);
  for (i = 1; i < size; i++)
    SET_SUB(node, l.subs[i], va_arg(ap, objc_node_t));

  return node;
}

objc_node_t
objc_make_bin_expr_node(int type,
                       objc_node_t left,
                       const char *op,
                       objc_node_t right)
{
  objc_node_t node;

  node = objc_make_node(type);
  SET_SUB(node, bin_expr.left, left);
  node->a.bin_expr.op = op;
  SET_SUB(node, bin_expr.right, right);

  return node;
}

void
objc_node_add(objc_node_t self, objc_node_t node)
{
  self->a.l.nsubs++;
  REALLOC_N(self->a.l.subs, objc_node_t, self->a.l.nsubs);
  SET_SUB(self, l.subs[self->a.l.nsubs-1], node);
}

void
objc_node_add_str(objc_node_t node, const char *s)
{
  objc_str_list_add_set(&node->a.strs, s);
}

void
objc_node_insert(objc_node_t self, objc_node_t node)
{
  size_t i = 0;

  self->a.l.nsubs++;
  REALLOC_N(self->a.l.subs, objc_node_t, self->a.l.nsubs);
  for (i = self->a.l.nsubs; i > 0; i--)
    self->a.l.subs[i] = self->a.l.subs[i-1];
  SET_SUB(self, l.subs[0], node);
}

const char *
objc_node_name(objc_node_t node)
{
  switch (node->type) {
  case OBJC_ABS_DCLR_NODE:
    return "abstract-declarator";
  case OBJC_ADD_EXPR_NODE:
    return "additive-expression";
  case OBJC_AND_EXPR_NODE:
    return "and-expression";
  case OBJC_ARG_EXPR_LIST_NODE:
    return "argument-expression-list";
  case OBJC_ARRAY_DIR_DCLR_NODE:
    return "array-direct-declarator";
  case OBJC_ARRAY_REF_EXPR_NODE:
    return "array-reference-expression";
  case OBJC_ASSIGN_EXPR_NODE:
    return "assignment-expression";
  case OBJC_ASSIGN_OP_NODE:
    return "assignment-operator";
  case OBJC_BASE_DCLR_NODE:
    return "base-declarator";
  case OBJC_CAST_EXPR_NODE:
    return "cast-expression";
  case OBJC_CAT_INTF_NODE:
    return "category-interface";
  case OBJC_CAT_INTF_DECL_LIST_NODE:
    return "category-interface-declaration-list";
  case OBJC_CAT_IMPL_NODE:
    return "category-implementation";
  case OBJC_CAT_SPCR_NODE:
    return "category-specifier";
  case OBJC_CLS_DECL_NODE:
    return "class-declaration";
  case OBJC_CLS_DCLR_LIST_NODE:
    return "class-declarator-list";
  case OBJC_CLS_INTF_NODE:
    return "class-interface";
  case OBJC_CLS_INTF_DECL_NODE:
    return "class-interface-declaration";
  case OBJC_CLS_IMPL_NODE:
    return "class-implementation";
  case OBJC_CLS_NAME_NODE:
    return "class-name";
  case OBJC_CLS_OBJ_RECV_NODE:
    return "class-object-receiver";
  case OBJC_CLS_SPCR_NODE:
    return "class-specifier";
  case OBJC_CLS_TYPE_NODE:
    return "class-type";
  case OBJC_CLS_TYPE_SPCR_NODE:
    return "class-type-specifier";
  case OBJC_COMPOUND_STMT_NODE:
    return "compound-statement";
  case OBJC_COND_EXPR_NODE:
    return "conditional-expression";
  case OBJC_CONST_NODE:
    return "constant";
  case OBJC_CONST_DIR_ABS_DCLR_NODE:
    return "constant-direct-abstract-declarator";
  case OBJC_DECL_NODE:
    return "declaration";
  case OBJC_DECL_SPCR_NODE:
    return "declaration-specifier";
  case OBJC_DECL_SPCR_LIST_NODE:
    return "declaration-specifier-list";
  case OBJC_DCLR_NODE:
    return "declarator";
  case OBJC_DECL_LIST_NODE:
    return "declaration-list";
  case OBJC_DIR_ABS_DCLR_NODE:
    return "direct-abstract-declarator";
  case OBJC_DIR_DCLR_NODE:
    return "direct-declarator";
  case OBJC_EMBED_TYPE_SPCR_NODE:
    return "embedded-type-specifier";
  case OBJC_ENC_EXPR_NODE:
    return "encode-expression";
  case OBJC_ENUM_NODE:
    return "enumerator";
  case OBJC_ENUM_LIST_NODE:
    return "enumerator-list";
  case OBJC_ENUM_SPCR_NODE:
    return "enum-specifier";
  case OBJC_EQ_EXPR_NODE:
    return "equality-expression";
  case OBJC_EXCL_OR_EXPR_NODE:
    return "exclusive-or-expression";
  case OBJC_EXPR_NODE:
    return "expression";
  case OBJC_XDECL_NODE:
    return "external-declaration";
  case OBJC_EXPR_STMT_NODE:
    return "expression-statement";
  case OBJC_FUNC_CALL_EXPR_NODE:
    return "function-call-expression";
  case OBJC_FUNC_DEF_NODE:
    return "function-definition";
  case OBJC_FUNC_DIR_DCLR_NODE:
    return "function-direct-declarator";
  case OBJC_GCC_ASM_CLOB_LIST_NODE:
    return "gcc-asm-clobber-list";
  case OBJC_GCC_ASM_OP_NODE:
    return "gcc-asm-operand";
  case OBJC_GCC_ASM_OP_LIST_NODE:
    return "gcc-asm-operand-list";
  case OBJC_GCC_ASM_OPT_LIST_NODE:
    return "gcc-asm-option-list";
  case OBJC_GCC_ASM_NODE:
    return "gcc-assembly";
  case OBJC_GCC_ASM_STMT_NODE:
    return "gcc-asm-statement";
  case OBJC_GCC_ATTR_SPCR_NODE:
    return "gcc-attribute-specifier";
  case OBJC_GCC_DIR_ATTR_SPCR_NODE:
    return "gcc-direct-attribute-specifier";
  case OBJC_GCC_DIR_ATTR_SPCR_LIST_NODE:
    return "gcc-direct-attribute-specifier-list";
  case OBJC_IDENT_NODE:
    return "identifier";
  case OBJC_IDENT_LIST_NODE:
    return "identifier-list";
  case OBJC_IMPL_DEF_NODE:
    return "implementation-definition";
  case OBJC_IMPL_DEF_LIST_NODE:
    return "implementation-definition-list";
  case OBJC_INCL_OR_EXPR_NODE:
    return "inclusive-or-expression";
  case OBJC_INC_OR_DEC_EXPR_NODE:
    return "increment-or-decrement-expression";
  case OBJC_INIT_DCLR_NODE:
    return "init-declarator";
  case OBJC_INIT_DCLR_LIST_NODE:
    return "init-declarator-list";
  case OBJC_INTR_NODE:
    return "initializer";
  case OBJC_INTR_LIST_NODE:
    return "initializer-list";
  case OBJC_IVAR_DECL_NODE:
    return "instance-variable-declaration";
  case OBJC_IVAR_DECL_LIST_NODE:
    return "instance-variable-declaration-list";
  case OBJC_IVAR_LIST_NODE:
    return "instance-variable-list";
  case OBJC_INTF_DECL_NODE:
    return "interface-declaration";
  case OBJC_INTF_DECL_LIST_NODE:
    return "interface-declaration-list";
  case OBJC_ITER_STMT_NODE:
    return "iteration-statement";
  case OBJC_JUMP_STMT_NODE:
    return "jump-statement";
  case OBJC_KW_ARG_EXPR_NODE:
    return "keyword-argument-expression";
  case OBJC_KW_ARG_EXPR_LIST_NODE:
    return "keyword-argument-expression-list";
  case OBJC_KW_ARG_SEL_NODE:
    return "keyword-argument-selector";
  case OBJC_KW_DCLR_NODE:
    return "keyword-declarator";
  case OBJC_KW_MSG_EXPR_NODE:
    return "keyword-message-expression";
  case OBJC_KW_SEL_NODE:
    return "keyword-selector";
  case OBJC_LABEL_STMT_NODE:
    return "labeled-statement";
  case OBJC_LOG_OR_EXPR_NODE:
    return "logical-or-expression";
  case OBJC_LOG_AND_EXPR_NODE:
    return "logical-and-expression";
  case OBJC_MTH_DECL_NODE:
    return "method-declaration";
  case OBJC_MTH_DCLR_NODE:
    return "method-declarator";
  case OBJC_MTH_DEF_NODE:
    return "method-definition";
  case OBJC_MTH_KW_SEL_NODE:
    return "method-keyword-selector";
  case OBJC_MTH_QUAL_NODE:
    return "method-qualifier";
  case OBJC_MTH_QUAL_LIST_NODE:
    return "method-qualifier-list";
  case OBJC_MTH_SPCR_NODE:
    return "method-specifier";
  case OBJC_MTH_TYPE_NODE:
    return "method-type";
  case OBJC_MTH_UNARY_SEL_NODE:
    return "method-unary-selector";
  case OBJC_MSG_EXPR_NODE:
    return "message-expression";
  case OBJC_MULTI_EXPR_NODE:
    return "multiplicative-expression";
  case OBJC_OBJC_STR_NODE:
    return "objective-c-string";
  case OBJC_PARAM_DECL_NODE:
    return "parameter-declaration";
  case OBJC_PARAM_DIR_ABS_DCLR_NODE:
    return "parameter-direct-abstract-declarator";
  case OBJC_PARAM_LIST_NODE:
    return "parameter-list";
  case OBJC_PARAM_TYPE_LIST_NODE:
    return "parameter-type-list";
  case OBJC_PTR_NODE:
    return "pointer";
  case OBJC_PRIM_EXPR_NODE:
    return "primary-expression";
  case OBJC_PRTC_DECL_NODE:
    return "protocol-declaration";
  case OBJC_PRTC_EXPR_NODE:
    return "protocol-expression";
  case OBJC_PRTC_LIST_NODE:
    return "protocol-list";
  case OBJC_PRTC_REF_LIST_NODE:
    return "protocol-reference-list";  
  case OBJC_RECV_NODE:
    return "receiver";
  case OBJC_RECV_TYPE_NODE:
    return "receiver-type";
  case OBJC_REL_EXPR_NODE:
    return "relational-expression";
  case OBJC_SEALED_NODE:
    return "sealed";
  case OBJC_SELECT_STMT_NODE:
    return "selection-statement";
  case OBJC_SEL_EXPR_NODE:
    return "selector-expression";
  case OBJC_SHIFT_EXPR_NODE:
    return "shift-expression";
  case OBJC_SIZE_EXPR_NODE:
    return "size-expression";
  case OBJC_SIZE_TYPE_EXPR_NODE:
    return "size-type-expression";
  case OBJC_SPCR_QUAL_LIST_NODE:
    return "specifier-qualifier-list";
  case OBJC_STMT_NODE:
    return "statement";
  case OBJC_STMT_LIST_NODE:
    return "statement-list";
  case OBJC_STORAGE_CLS_SPCR_NODE:
    return "storage-class-specifier";
  case OBJC_STR_NODE:
    return "string";
  case OBJC_STRUCT_DECL_NODE:
    return "struct-declaration";
  case OBJC_STRUCT_DECL_LIST_NODE:
    return "struct-declaration-list";
  case OBJC_STRUCT_DCLR_NODE:
    return "struct-declarator";
  case OBJC_STRUCT_DCLR_LIST_NODE:
    return "struct-declarator-list";
  case OBJC_SU_NODE:
    return "struct-or-union";
  case OBJC_SU_REF_EXPR_NODE:
    return "struct-or-union-reference-expression";
  case OBJC_SU_SPCR_NODE:
    return "struct-or-union-specifier";
  case OBJC_SUPER_NODE:
    return "super";
  case OBJC_SCLS_NAME_NODE:
    return "superclass-name";
  case OBJC_TUNIT_NODE:
    return "transaction-unit";
  case OBJC_TYPE_NAME_NODE:
    return "type-name";
  case OBJC_TYPEDEF_NAME_NODE:
    return "typedef-name";
  case OBJC_TYPE_SPCR_NODE:
    return "type-specifier";
  case OBJC_TYPE_QUAL_NODE:
    return "type-qualifier";
  case OBJC_TYPE_QUAL_LIST_NODE:
    return "type-qualifier-list";
  case OBJC_URARY_OP_NODE:
    return "unary-operator";
  case OBJC_UNARY_OP_EXPR_NODE:
    return "unary-operator-expression";
  case OBJC_UNARY_MSG_EXPR_NODE:
    return "unary-message-expression";
  case OBJC_UNARY_MSG_SEL_NODE:
    return "unary-message-selector";
  case OBJC_VSBL_SPEC_NODE:
    return "visibility-specification";
  default:
    return "unknown node";
  }
}

struct objc_scope *
objc_node_scope(objc_node_t node)
{
  while (node->scope == NULL && node->parent != NULL)
    node = node->parent;
  return node->scope;
}

int
objc_node_has_type_ptr_size(objc_node_t node)
{
  int i;
  objc_scope_entry_t entry;
#ifdef HAVE_LONG_LONG
  int may_long2 = 0;
#endif /* HAVE_LONG_LONG */

  if (node == NULL)
    return 0;

  switch (node->type) {
  case OBJC_DECL_SPCR_LIST_NODE:
  case OBJC_SPCR_QUAL_LIST_NODE:
    for (i = 0; i < node->a.l.nsubs; i++) {
      switch (objc_node_has_type_ptr_size(node->a.l.subs[i])) {
      case 0:
        return 0;
#ifdef HAVE_LONG_LONG
      case -1:
        if (may_long2)
          return 0;
        else
          may_long2 = 1;
        break;
#endif /* HAVE_LONG_LONG */
      }
    }
#ifdef HAVE_LONG_LONG
    return sizeof(void *) >= sizeof(long);
#else
    return 1;
#endif /* HAVE_LONG_LONG */

  case OBJC_TYPE_NAME_NODE:
    return node->a.type_name.abs_dclr != NULL ||
      objc_node_has_type_ptr_size(node->a.type_name.spcr_qual_list);

  case OBJC_TYPE_SPCR_NODE:
    switch (node->a.word) {
    case CHAR:      return sizeof(void *) >= sizeof(char);
    case SHORT:     return sizeof(void *) >= sizeof(short);
    case INT:       return sizeof(void *) >= sizeof(int);
    case FLOAT:     return sizeof(void *) >= sizeof(float);
    case DOUBLE:    return sizeof(void *) >= sizeof(double);
    case LONG:
#ifdef HAVE_LONG_LONG
      return -1;
#else
      return sizeof(void *) >= sizeof(long);
#endif /* HAVE_LONG_LONG */
    default:
      return 1;
    }

  case OBJC_TYPEDEF_NAME_NODE:
    entry = objc_scope_get_type(objc_current_scope, node->a.sval);
    switch (entry->type) {
    case OBJC_TYPE_NAME:
      return objc_node_has_type_ptr_size(entry->a.type.dclr) ||
        objc_node_has_type_ptr_size(entry->a.type.spcr);
    }
    objc_print_error(__FILE__ ": objc_node_has_type_ptr_size(): "
                    "%s: not supported type", entry->name);

  case OBJC_IDENT_NODE:
    entry = objc_scope_get_type(objc_root_scope, node->a.sval);
    if (entry != NULL) {
      switch (entry->type) {
        case OBJC_CLASS_NAME:
        case OBJC_SELF:
          return 1;

        case OBJC_ENUM_NAME:
          return sizeof(int) <= sizeof(void *);

        case OBJC_TYPE_NAME:
          return objc_node_has_type_ptr_size(entry->a.type.spcr);

         /* FIXME */
        case OBJC_COMPILER_BUILTIN:
        case OBJC_STRUCT_NAME:
        case OBJC_UNION_NAME:
        case OBJC_VAR_NAME:
          break;
      }
      /* FIXME */
      objc_print_error(__FILE__ ": objc_node_has_type_ptr_size(): "
                       "not supported entry %d\n", entry->type);
      return 0;
    } else {
      /* FIXME */
      objc_print_error(__FILE__ ": objc_node_has_type_ptr_size(): "
                       "unknown identifier %s\n", node->a.sval);
      return 0;
    }

  case OBJC_INIT_DCLR_NODE:
    return objc_node_has_type_ptr_size(node->a.init_dclr.dclr);

  case OBJC_DCLR_NODE:
    return objc_node_has_type_ptr_size(node->a.dclr.base_dclr);

  case OBJC_BASE_DCLR_NODE:
    return node->a.base_dclr.ptr != NULL ||
      objc_node_has_type_ptr_size(node->a.base_dclr.dir_dclr);

  case OBJC_SU_SPCR_NODE:
    return 0;

  default:
    objc_print_error(__FILE__ ": objc_node_has_type_ptr_size(): "
                    "%s: not supported", objc_node_name(node));
    return 0;
  }
}

int
objc_list_node_not_empty(objc_node_t node)
{
  return node != NULL && node->a.l.nsubs > 0;
}

char *
objc_node_recv_cache_var(objc_node_t node __attribute__((unused)))
{
  /* FIXME */
  static char *var = NULL;
  if (var == NULL)
    var = objc_strdup(DEFAULT_RECV_CACHE_VAR);
  return var;
}

char *
objc_node_get_method_name(objc_node_t node)
{
  switch (node->type) {
  case OBJC_MTH_DEF_NODE:
    return objc_node_get_method_name(node->a.mth_def.mth_dclr->a.mth_dclr.mth_sel);
  case OBJC_MTH_UNARY_SEL_NODE:
    return node->a.sval;
  case OBJC_MTH_KW_SEL_NODE:
    return node->a.mth_kw_sel.name;
  }
  return NULL;
}

char *
objc_node_get_ident_name(objc_node_t node)
{
  switch (node->type) {
  case OBJC_IDENT_NODE:
    return node->a.sval;

  case OBJC_DCLR_NODE:
    return objc_node_get_ident_name(node->a.dclr.base_dclr);

  case OBJC_BASE_DCLR_NODE:
    return objc_node_get_ident_name(node->a.base_dclr.dir_dclr);

  case OBJC_ARRAY_DIR_DCLR_NODE:
    return objc_node_get_ident_name(node->a.array_dir_dclr.dir_dclr);

  case OBJC_FUNC_DIR_DCLR_NODE:
    return objc_node_get_ident_name(node->a.func_dir_dclr.dir_dclr);

  default:
    objc_print_error("objc_node_get_ident_name: not supported %s\n",
                      objc_node_name(node));
  }
  return NULL;
}

objc_node_t
objc_make_abs_dclr_node(objc_node_t ptr, objc_node_t dir_abs_dclr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_ABS_DCLR_NODE);
  SET_SUB(node, abs_dclr.ptr, ptr);
  SET_SUB(node, abs_dclr.dir_abs_dclr, dir_abs_dclr);

  return node;
}

objc_node_t
objc_make_add_expr_node(objc_node_t left, const char *op, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_ADD_EXPR_NODE, left, op, right);
}

objc_node_t
objc_make_and_expr_node(objc_node_t left, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_AND_EXPR_NODE, left, "&", right);
}

objc_node_t
objc_make_arg_expr_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_ARG_EXPR_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_array_ref_expr_node(objc_node_t array, objc_node_t ref)
{
  objc_node_t node;

  node = objc_make_node(OBJC_ARRAY_REF_EXPR_NODE);
  SET_SUB(node, array_ref_expr.array, array);
  SET_SUB(node, array_ref_expr.ref, ref);

  return node;
}

objc_node_t
objc_make_array_dir_dclr_node(objc_node_t dir_dclr, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_ARRAY_DIR_DCLR_NODE);
  SET_SUB(node, array_dir_dclr.dir_dclr, dir_dclr);
  SET_SUB(node, array_dir_dclr.expr, expr);

  return node;
}

objc_node_t
objc_make_assign_expr_node(objc_node_t left, const char *op, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_ASSIGN_EXPR_NODE, left, op, right);
}

objc_node_t
objc_make_base_dclr_node(objc_node_t ptr, objc_node_t dir_dclr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_BASE_DCLR_NODE);
  SET_SUB(node, base_dclr.ptr, ptr);
  SET_SUB(node, base_dclr.dir_dclr, dir_dclr);

  return node;
}

objc_node_t
objc_make_cast_expr_node(objc_node_t type, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CAST_EXPR_NODE);
  SET_SUB(node, cast_expr.type, type);
  SET_SUB(node, cast_expr.expr, expr);

  return node;
}

objc_node_t
objc_make_cat_impl_node(objc_node_t cat_spcr, objc_node_t impl_def_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CAT_IMPL_NODE);
  SET_SUB(node, cat_impl.cat_spcr, cat_spcr);
  SET_SUB(node, cat_impl.impl_def_list, impl_def_list);

  return node;
}

objc_node_t
objc_make_cat_intf_node(objc_node_t cat_spcr, objc_node_t cat_intf_decl_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CAT_INTF_NODE);
  SET_SUB(node, cat_intf.cat_spcr, cat_spcr);
  SET_SUB(node, cat_intf.cat_intf_decl_list, cat_intf_decl_list);

  return node;
}

objc_node_t
objc_make_cat_intf_decl_list_node(objc_node_t prtc_ref_list,
                                  objc_node_t intf_decl_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CAT_INTF_DECL_LIST_NODE);
  SET_SUB(node, cat_intf_decl_list.prtc_ref_list, prtc_ref_list);
  SET_SUB(node, cat_intf_decl_list.intf_decl_list, intf_decl_list);

  return node;
}

objc_node_t
objc_make_cat_spcr_node(const char *cls_name, const char *cat_name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CAT_SPCR_NODE);
  node->a.cat_spcr.cls_name = objc_strdup(cls_name);
  node->a.cat_spcr.cat_name = objc_strdup(cat_name);

  return node;
}

objc_node_t
objc_make_cls_decl_node(objc_node_t list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CLS_DECL_NODE);
  SET_SUB(node, node, list);

  return node;
}

objc_node_t
objc_make_cls_dclr_list_node(const char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CLS_DCLR_LIST_NODE);
  node->a.strs = objc_make_str_list(name, NULL);

  return node;
}

objc_node_t
objc_make_cls_impl_node(objc_node_t cls_spcr, objc_node_t impl_def_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CLS_IMPL_NODE);
  SET_SUB(node, cls_impl.cls_spcr, cls_spcr);
  SET_SUB(node, cls_impl.impl_def_list, impl_def_list);

  return node;
}

objc_node_t
objc_make_cls_intf_node(objc_node_t cls_spcr, objc_node_t cls_intf_decl)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CLS_INTF_NODE);
  SET_SUB(node, cls_intf.cls_spcr, cls_spcr);
  SET_SUB(node, cls_intf.cls_intf_decl, cls_intf_decl);

  return node;
}

objc_node_t
objc_make_cls_intf_decl_node(objc_node_t prtc_ref_list,
                             objc_node_t ivar_list,
                             objc_node_t intf_decl_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CLS_INTF_DECL_NODE);
  SET_SUB(node, cls_intf_decl.prtc_ref_list, prtc_ref_list);
  SET_SUB(node, cls_intf_decl.ivar_list, ivar_list);
  SET_SUB(node, cls_intf_decl.intf_decl_list, intf_decl_list);

  return node;
}

objc_node_t
objc_make_cls_name_node(const char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CLS_NAME_NODE);
  node->a.sval = objc_strdup(name);

  return node;
}

objc_node_t
objc_make_cls_obj_recv_node(const char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CLS_OBJ_RECV_NODE);
  node->a.sval = objc_strdup(name);

  return node;
}

objc_node_t
objc_make_cls_spcr_node(const char *name, const char *super_name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CLS_SPCR_NODE);
  node->a.cls_spcr.name = objc_strdup(name);
  if (super_name != NULL)
    node->a.cls_spcr.super_name = objc_strdup(super_name);
  else
    node->a.cls_spcr.super_name = NULL;
  
  return node;
}

objc_node_t
objc_make_compound_stmt_node(objc_node_t decl_list, objc_node_t stmt_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_COMPOUND_STMT_NODE);
  SET_SUB(node, compound_stmt.decl_list, decl_list);
  SET_SUB(node, compound_stmt.stmt_list, stmt_list);

  return node;
}

objc_node_t
objc_make_cond_expr_node(objc_node_t cond,
                         objc_node_t t_expr,
                         objc_node_t f_expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_COND_EXPR_NODE);
  SET_SUB(node, cond_expr.cond, cond);
  SET_SUB(node, cond_expr.t_expr, t_expr);
  SET_SUB(node, cond_expr.f_expr, f_expr);

  return node;
}

objc_node_t
objc_make_const_node(int tag, char *s)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CONST_NODE);
  node->a.const_val.tag = tag;
  node->a.const_val.val = s;

  return node;
}

objc_node_t
objc_make_const_dir_abs_dclr_node(objc_node_t dir_dir_abs_dclr, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_CONST_DIR_ABS_DCLR_NODE);
  SET_SUB(node, const_dir_abs_dclr.dir_abs_dclr, dir_dir_abs_dclr);
  SET_SUB(node, const_dir_abs_dclr.expr, expr);

  return node;
}

objc_node_t
objc_make_decl_node(objc_node_t decl_spcr_list, objc_node_t init_dclr_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_DECL_NODE);
  SET_SUB(node, decl.decl_spcr_list, decl_spcr_list);
  SET_SUB(node, decl.init_dclr_list, init_dclr_list);

  return node;
}

objc_node_t
objc_make_decl_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_DECL_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_decl_spcr_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_DECL_SPCR_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_dclr_node(objc_node_t base_dclr,
                    objc_node_t gcc_attr_spcr,
                    objc_node_t gcc_asm)
{
  objc_node_t node;

  node = objc_make_node(OBJC_DCLR_NODE);
  SET_SUB(node, dclr.base_dclr, base_dclr);
  SET_SUB(node, dclr.gcc_attr_spcr, gcc_attr_spcr);
  SET_SUB(node, dclr.gcc_asm, gcc_asm);

  return node;
}

char *
objc_node_dclr_name(objc_node_t node)
{
  if (!node)
    return NULL;

  switch (node->type) {
  case OBJC_ABS_DCLR_NODE:
    return objc_node_dclr_name(node->a.abs_dclr.dir_abs_dclr);
  case OBJC_CONST_DIR_ABS_DCLR_NODE:
    return objc_node_dclr_name(node->a.const_dir_abs_dclr.dir_abs_dclr);
  case OBJC_FUNC_DEF_NODE:
    return objc_node_dclr_name(node->a.func_def.dclr);
  case OBJC_MTH_DCLR_NODE:
    return objc_node_dclr_name(node->a.mth_dclr.mth_sel);
  case OBJC_MTH_UNARY_SEL_NODE:
    return node->a.sval;
  case OBJC_MTH_KW_SEL_NODE:
    return node->a.mth_kw_sel.name;
  case OBJC_STRUCT_DCLR_NODE:
    return objc_node_dclr_name(node->a.struct_dclr.dclr);
  case OBJC_TYPE_NAME_NODE:
    return objc_node_dclr_name(node->a.type_name.abs_dclr);
  case OBJC_INIT_DCLR_NODE:
    return objc_node_dclr_name(node->a.init_dclr.dclr);
  case OBJC_DCLR_NODE:
    return objc_node_dclr_name(node->a.dclr.base_dclr);
  case OBJC_BASE_DCLR_NODE:
    return objc_node_dclr_name(node->a.base_dclr.dir_dclr);
  case OBJC_IDENT_NODE:
    return node->a.sval;
  case OBJC_ARRAY_DIR_DCLR_NODE:
    return objc_node_dclr_name(node->a.array_dir_dclr.dir_dclr);
  case OBJC_FUNC_DIR_DCLR_NODE:
    return objc_node_dclr_name(node->a.func_dir_dclr.dir_dclr);
  case OBJC_PARAM_DIR_ABS_DCLR_NODE:
    if (node->a.param_dir_abs_dclr.dir_abs_dclr)
      return objc_node_dclr_name(node->a.func_dir_dclr.dir_dclr);
    else
      return NULL;
  default:
    objc_print_error("objc_node_dclr_name: unknown node %s",
                    objc_node_name(node));
    return NULL;
  }
}

objc_node_t
objc_make_enc_expr_node(objc_node_t type)
{
  objc_node_t node;

  node = objc_make_node(OBJC_ENC_EXPR_NODE);
  SET_SUB(node, node, type);

  return node;
}

objc_node_t
objc_make_enum_node(char *name, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_ENUM_NODE);
  node->a.enmr.name = name;
  SET_SUB(node, enmr.expr, expr);

  return node;
}

objc_node_t
objc_make_enum_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_ENUM_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_enum_spcr_node(const char *name, objc_node_t enum_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_ENUM_SPCR_NODE);
  if (name != NULL)
    node->a.enum_spcr.name = objc_strdup(name);
  else
    node->a.enum_spcr.name = NULL;
  SET_SUB(node, enum_spcr.enum_list, enum_list);

  return node;
}

objc_node_t
objc_make_eq_expr_node(objc_node_t left, const char *op, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_EQ_EXPR_NODE, left, op, right);
}

objc_node_t
objc_make_exc_or_expr_node(objc_node_t left, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_EXCL_OR_EXPR_NODE, left, "^", right);
}

objc_node_t
objc_make_expr_node(objc_node_t expr)
{
  return objc_make_list_node(OBJC_EXPR_NODE, expr, NULL);
}

objc_node_t
objc_make_expr_stmt_node(objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_EXPR_STMT_NODE);
  SET_SUB(node, node, expr);

  return node;
}

objc_node_t
objc_make_func_call_expr_node(objc_node_t func, objc_node_t arg)
{
  objc_node_t node;

  node = objc_make_node(OBJC_FUNC_CALL_EXPR_NODE);
  SET_SUB(node, func_call_expr.func, func);
  SET_SUB(node, func_call_expr.arg, arg);

  return node;
}

objc_node_t
objc_make_func_def_node(objc_node_t decl_spcr_list,
                        objc_node_t dclr,
                        objc_node_t decl_list,
                        objc_node_t stmt)
{
  objc_node_t node;

  node = objc_make_node(OBJC_FUNC_DEF_NODE);
  SET_SUB(node, func_def.decl_spcr_list, decl_spcr_list);
  SET_SUB(node, func_def.dclr, dclr);
  SET_SUB(node, func_def.decl_list, decl_list);
  SET_SUB(node, func_def.stmt, stmt);

  return node;
}

objc_node_t
objc_make_func_dir_dclr_node(objc_node_t dir_dclr, objc_node_t param_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_FUNC_DIR_DCLR_NODE);
  SET_SUB(node, func_dir_dclr.dir_dclr, dir_dclr);
  SET_SUB(node, func_dir_dclr.param_list, param_list);

  return node;
}

objc_node_t
objc_make_gcc_asm_node(const char *asm_word,
                       const char *volatile_word,
                       char *stmt,
                       objc_node_t opts)
{
  objc_node_t node;

  node = objc_make_node(OBJC_GCC_ASM_NODE);
  node->a.gcc_asm.asm_word = asm_word;
  node->a.gcc_asm.volatile_word = volatile_word;
  node->a.gcc_asm.stmt = stmt;
  SET_SUB(node, gcc_asm.opts, opts);

  return node;
}

objc_node_t
objc_make_gcc_asm_opt_list_node(objc_node_t out_op,
                                objc_node_t in_op,
                                objc_node_t clob)
{
  objc_node_t node;

  node = objc_make_node(OBJC_GCC_ASM_OPT_LIST_NODE);
  SET_SUB(node, gcc_asm_opts.out_op, out_op);
  SET_SUB(node, gcc_asm_opts.in_op, in_op);
  SET_SUB(node, gcc_asm_opts.clob, clob);

  return node;
}

objc_node_t
objc_make_gcc_asm_op_list_node(objc_node_t op)
{
  objc_node_t node;

  node = objc_make_node(OBJC_GCC_ASM_OP_LIST_NODE);
  objc_node_add(node, op);

  return node;
}

objc_node_t
objc_make_gcc_asm_op_node(char *stmt, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_GCC_ASM_OP_NODE);
  node->a.gcc_asm_op.stmt = stmt;
  SET_SUB(node, gcc_asm_op.expr, expr);

  return node;
}

objc_node_t
objc_make_gcc_asm_clob_list_node(char *clob)
{
  objc_node_t node;

  node = objc_make_node(OBJC_GCC_ASM_CLOB_LIST_NODE);
  node->a.strs = objc_make_str_list(clob, NULL);

  return node;
}

objc_node_t
objc_make_gcc_asm_stmt_node(objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_GCC_ASM_STMT_NODE);
  node->a.node = expr;
  
  return node;
}
  
objc_node_t
objc_make_gcc_attr_spcr_node(objc_node_t dir)
{
  objc_node_t node;

  node = objc_make_node(OBJC_GCC_ATTR_SPCR_NODE);
  SET_SUB(node, node, dir);

  return node;
}

objc_node_t objc_make_gcc_dir_attr_spcr_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_GCC_DIR_ATTR_SPCR_LIST_NODE, sub, NULL);
}

objc_node_t objc_make_gcc_dir_attr_spcr_node(char *name, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_GCC_DIR_ATTR_SPCR_NODE);
  node->a.gcc_dir_attr_spcr.name = name;
  SET_SUB(node, gcc_dir_attr_spcr.expr, expr);

  return node;
}

objc_node_t
objc_make_ident_node(char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_IDENT_NODE);
  node->a.sval = name;

  return node;
}

objc_node_t
objc_make_ident_list_node(char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_IDENT_LIST_NODE);
  node->a.strs = objc_make_str_list(name, NULL);

  return node;
}

objc_node_t
objc_make_impl_def_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_IMPL_DEF_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_incl_or_expr_node(objc_node_t left, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_INCL_OR_EXPR_NODE, left, "|", right);
}

objc_node_t
objc_make_inc_or_dec_expr_node(int prefix, const char *op, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_INC_OR_DEC_EXPR_NODE);
  node->a.inc_or_dec_expr.prefix = prefix;
  node->a.inc_or_dec_expr.op = objc_strdup(op);
  SET_SUB(node, inc_or_dec_expr.expr, expr);

  return node;

}

objc_node_t
objc_make_init_dclr_node(objc_node_t dclr, objc_node_t init)
{
  objc_node_t node;

  node = objc_make_node(OBJC_INIT_DCLR_NODE);
  SET_SUB(node, init_dclr.dclr, dclr);
  SET_SUB(node, init_dclr.init, init);

  return node;
}

objc_node_t
objc_make_init_dclr_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_INIT_DCLR_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_intr_node(objc_node_t list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_INTR_NODE);
  SET_SUB(node, node, list);

  return node;
}

objc_node_t
objc_make_intr_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_INTR_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_intf_decl_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_INTF_DECL_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_iter_stmt_node(int tag,
                         objc_node_t init,
                         objc_node_t cond,
                         objc_node_t action,
                         objc_node_t stmt)
{
  objc_node_t node;

  node = objc_make_node(OBJC_ITER_STMT_NODE);
  node->a.iter_stmt.tag = tag;
  SET_SUB(node, iter_stmt.init, init);
  SET_SUB(node, iter_stmt.cond, cond);
  SET_SUB(node, iter_stmt.action, action);
  SET_SUB(node, iter_stmt.stmt, stmt);

  return node;
}

objc_node_t
objc_make_ivar_decl_node(objc_node_t spcr_qual_list, objc_node_t dclr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_IVAR_DECL_NODE);
  SET_SUB(node, ivar_decl.spcr_qual_list, spcr_qual_list);
  SET_SUB(node, ivar_decl.dclr, dclr);

  return node;
}

objc_node_t
objc_make_ivar_decl_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_IVAR_DECL_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_jump_stmt_node(int tag, objc_node_t expr, char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_JUMP_STMT_NODE);
  node->a.jump_stmt.tag = tag;
  SET_SUB(node, jump_stmt.expr, expr);
  node->a.jump_stmt.name = name;

  return node;

}

objc_node_t
objc_make_kw_arg_expr_node(size_t name_lc, size_t colon_lc,
                           char *name, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_KW_ARG_EXPR_NODE);
  node->a.kw_arg_expr.name_lc = name_lc;
  node->a.kw_arg_expr.colon_lc = colon_lc;
  node->a.kw_arg_expr.name = name;
  SET_SUB(node, kw_arg_expr.expr, expr);

  return node;
}

objc_node_t
objc_make_kw_arg_expr_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_KW_ARG_EXPR_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_kw_dclr_node(char *name, objc_node_t mtype, char *arg)
{
  objc_node_t node;

  node = objc_make_node(OBJC_KW_DCLR_NODE);
  node->a.kw_dclr.name = name;
  SET_SUB(node, kw_dclr.mtype, mtype);
  node->a.kw_dclr.arg = arg;

  return node;
}

objc_node_t
objc_make_kw_msg_expr_node(objc_node_t recv,
                           char *sel_name,
                           objc_node_t arg_list,
                           BOOL self_is_inst)
{
  objc_node_t node;

  node = objc_make_node(OBJC_KW_MSG_EXPR_NODE);
  SET_SUB(node, kw_msg_expr.recv, recv);
  node->a.kw_msg_expr.sel_name = sel_name;
  node->a.kw_msg_expr.self_is_inst = self_is_inst;
  SET_SUB(node, kw_msg_expr.arg_list, arg_list);

  return node;
}

objc_node_t
objc_make_kw_sel_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_KW_SEL_NODE, sub, NULL);
}

objc_node_t
objc_make_label_stmt_node(int tag, objc_node_t expr, objc_node_t stmt)
{
  objc_node_t node;

  node = objc_make_node(OBJC_LABEL_STMT_NODE);
  node->a.label_stmt.tag = tag;
  SET_SUB(node, label_stmt.expr, expr);
  SET_SUB(node, label_stmt.stmt, stmt);

  return node;
}

objc_node_t
objc_make_log_and_expr_node(objc_node_t left, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_LOG_AND_EXPR_NODE, left, "&&", right);
}

objc_node_t
objc_make_log_or_expr_node(objc_node_t left, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_LOG_OR_EXPR_NODE, left, "||", right);
}

objc_node_t
objc_make_mth_decl_node(objc_node_t mth_dclr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_MTH_DECL_NODE);
  SET_SUB(node, node, mth_dclr);

  return node;
}

objc_node_t
objc_make_mth_dclr_node(objc_node_t mth_qual_list,
                        objc_node_t mth_spcr,
                        objc_node_t mth_sel)
{
  objc_node_t node;

  node = objc_make_node(OBJC_MTH_DCLR_NODE);
  SET_SUB(node, mth_dclr.mth_qual_list, mth_qual_list);
  SET_SUB(node, mth_dclr.mth_spcr, mth_spcr);
  SET_SUB(node, mth_dclr.mth_sel, mth_sel);

  return node;
}

objc_node_t
objc_make_mth_def_node(objc_node_t mth_dclr,
                       objc_node_t decl_list,
                       objc_node_t stmt)
{
  objc_node_t node;

  node = objc_make_node(OBJC_MTH_DEF_NODE);
  SET_SUB(node, mth_def.mth_dclr, mth_dclr);
  SET_SUB(node, mth_def.decl_list, decl_list);
  SET_SUB(node, mth_def.stmt, stmt);

  return node;
}

objc_node_t
objc_make_mth_kw_sel_node(objc_node_t sel, char *name, int vargs)
{
  objc_node_t node;

  node = objc_make_node(OBJC_MTH_KW_SEL_NODE);
  SET_SUB(node, mth_kw_sel.sel, sel);
  node->a.mth_kw_sel.name = name;
  node->a.mth_kw_sel.vargs = vargs;

  return node;
}

objc_node_t
objc_make_mth_qual_node(int tag)
{
  objc_node_t node;

  node = objc_make_node(OBJC_MTH_QUAL_NODE);
  node->a.tag = tag;

  return node;
}

objc_node_t
objc_make_mth_qual_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_MTH_QUAL_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_mth_spcr_node(int rtype, objc_node_t mtype)
{
  objc_node_t node;

  node = objc_make_node(OBJC_MTH_SPCR_NODE);
  node->a.mth_spcr.rtype = rtype;
  SET_SUB(node, mth_spcr.mtype, mtype);

  return node;
}

objc_node_t
objc_make_mth_unary_sel_node(char *sel)
{
  objc_node_t node;

  node = objc_make_node(OBJC_MTH_UNARY_SEL_NODE);
  node->a.sval = sel;

  return node;
}

objc_node_t
objc_make_multi_expr_node(objc_node_t left, const char *op, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_MULTI_EXPR_NODE, left, op, right);
}

objc_node_t
objc_make_objc_str_node(char *s, int n)
{
  objc_node_t node;

  node = objc_make_node(OBJC_OBJC_STR_NODE);
  node->a.objc_str.s = s;
  node->a.objc_str.n = n;

  return node;

}

objc_node_t
objc_make_param_decl_node(objc_node_t decl_spcr_list,
                          objc_node_t dclr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_PARAM_DECL_NODE);
  SET_SUB(node, param_decl.decl_spcr_list, decl_spcr_list);
  SET_SUB(node, param_decl.dclr, dclr);

  return node;
}

objc_node_t
objc_make_param_dir_abs_dclr_node(objc_node_t dir_abs_dclr,
                                  objc_node_t param_type_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_PARAM_DIR_ABS_DCLR_NODE);
  SET_SUB(node, param_dir_abs_dclr.dir_abs_dclr, dir_abs_dclr);
  SET_SUB(node, param_dir_abs_dclr.param_type_list, param_type_list);

  return node;
}

objc_node_t
objc_make_param_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_PARAM_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_param_type_list_node(objc_node_t param_list, int vargs)
{
  objc_node_t node;

  node = objc_make_node(OBJC_PARAM_TYPE_LIST_NODE);
  SET_SUB(node, param_type_list.param_list, param_list);
  node->a.param_type_list.vargs = vargs;

  return node;
}

objc_node_t
objc_make_prtc_decl_node(char *name,
                         objc_node_t prtc_ref_list,
                         objc_node_t intf_decl_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_PRTC_DECL_NODE);
  node->a.prtc_decl.name = name;
  SET_SUB(node, prtc_decl.prtc_ref_list, prtc_ref_list);
  SET_SUB(node, prtc_decl.intf_decl_list, intf_decl_list);

  return node;
}

objc_node_t
objc_make_prtc_expr_node(const char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_PRTC_EXPR_NODE);
  node->a.sval = objc_strdup(name);

  return node;
}

objc_node_t
objc_make_prtc_list_node(const char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_PRTC_LIST_NODE);
  node->a.strs = objc_make_str_list(name, NULL);

  return node;
}

objc_node_t
objc_make_ptr_node(objc_node_t gcc_attr_spcr,
                   objc_node_t type_qual_list,
                   objc_node_t ptr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_PTR_NODE);
  SET_SUB(node, ptr.gcc_attr_spcr, gcc_attr_spcr);
  SET_SUB(node, ptr.type_qual_list, type_qual_list);
  SET_SUB(node, ptr.ptr, ptr);

  return node;
}

objc_node_t
objc_make_rel_expr_node(objc_node_t left, const char *op, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_REL_EXPR_NODE, left, op, right);
}

objc_node_t
objc_make_sel_expr_node(char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_SEL_EXPR_NODE);
  node->a.sval = name;

  return node;
}

objc_node_t
objc_make_select_stmt_node(int tag,
                           objc_node_t cond,
                           objc_node_t stmt,
                           objc_node_t else_stmt)
{
  objc_node_t node;

  node = objc_make_node(OBJC_SELECT_STMT_NODE);
  node->a.select_stmt.tag = tag;
  SET_SUB(node, select_stmt.cond, cond);
  SET_SUB(node, select_stmt.stmt, stmt);
  SET_SUB(node, select_stmt.else_stmt, else_stmt);

  return node;
}

objc_node_t
objc_make_shift_expr_node(objc_node_t left, const char *op, objc_node_t right)
{
  return objc_make_bin_expr_node(OBJC_SHIFT_EXPR_NODE, left, op, right);
}

objc_node_t
objc_make_size_expr_node(objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_SIZE_EXPR_NODE);
  SET_SUB(node, node, expr);

  return node;
}

objc_node_t
objc_make_size_type_expr_node(objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_SIZE_TYPE_EXPR_NODE);
  SET_SUB(node, node, expr);

  return node;
}

objc_node_t
objc_make_spcr_qual_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_SPCR_QUAL_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_storage_cls_spcr_node(int word)
{
  objc_node_t node;

  node = objc_make_node(OBJC_STORAGE_CLS_SPCR_NODE);
  node->a.word = word;

  return node;
}

objc_node_t
objc_make_stmt_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_STMT_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_str_node(const char *s)
{
  objc_node_t node;

  node = objc_make_node(OBJC_STR_NODE);
  node->a.sval = objc_strdup(s);

  return node;
}

int
objc_is_objc_str(objc_node_t self)
{
  return *(self->a.sval) == '@';
}

objc_node_t
objc_make_struct_decl_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_STRUCT_DECL_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_struct_decl_node(objc_node_t spcr_qual_list, objc_node_t dclr_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_STRUCT_DECL_NODE);
  SET_SUB(node, struct_decl.spcr_qual_list, spcr_qual_list);
  SET_SUB(node, struct_decl.dclr_list, dclr_list);

  return node;
}

objc_node_t
objc_make_struct_dclr_node(objc_node_t dclr, objc_node_t expr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_STRUCT_DCLR_NODE);
  SET_SUB(node, struct_dclr.dclr, dclr);
  SET_SUB(node, struct_dclr.expr, expr);

  return node;
}

objc_node_t
objc_make_struct_dclr_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_STRUCT_DCLR_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_su_ref_expr_node(objc_node_t expr, int dir, char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_SU_REF_EXPR_NODE);
  SET_SUB(node, su_ref_expr.expr, expr);
  node->a.su_ref_expr.dir = dir;
  node->a.su_ref_expr.name = name;

  return node;
}

objc_node_t
objc_make_su_spcr_node(int type, const char *name, objc_node_t decl_list)
{
  objc_node_t node;

  node = objc_make_node(OBJC_SU_SPCR_NODE);
  node->a.su_spcr.type = type;
  if (name != NULL)
    node->a.su_spcr.name = objc_strdup(name);
  else
    node->a.su_spcr.name = NULL;
  SET_SUB(node, su_spcr.decl_list, decl_list);

  return node;
}

objc_node_t
objc_make_super_node()
{
  return objc_make_node(OBJC_SUPER_NODE);
}

objc_node_t
objc_make_tunit_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_TUNIT_NODE, sub, NULL);
}

objc_node_t
objc_make_typedef_name_node(const char *name)
{
  objc_node_t node;

  node = objc_make_node(OBJC_TYPEDEF_NAME_NODE);
  node->a.sval = objc_strdup(name);

  return node;
}

objc_node_t
objc_make_type_name_node(objc_node_t spcr_qual_list, objc_node_t abs_dclr)
{
  objc_node_t node;

  node = objc_make_node(OBJC_TYPE_NAME_NODE);
  SET_SUB(node, type_name.spcr_qual_list, spcr_qual_list);
  SET_SUB(node, type_name.abs_dclr, abs_dclr);

  return node;
}

objc_node_t
objc_make_type_qual_list_node(objc_node_t sub)
{
  return objc_make_list_node(OBJC_TYPE_QUAL_LIST_NODE, sub, NULL);
}

objc_node_t
objc_make_type_spcr_node(int word)
{
  objc_node_t node;

  node = objc_make_node(OBJC_TYPE_SPCR_NODE);
  node->a.word = word;

  return node;
}

objc_node_t
objc_make_type_qual_node(int word)
{
  objc_node_t node;

  node = objc_make_node(OBJC_TYPE_QUAL_NODE);
  node->a.word = word;

  return node;
}

objc_node_t
objc_make_unary_msg_expr_node(objc_node_t recv,
                              char *sel_name,
                              BOOL self_is_inst)
{
  objc_node_t node;

  node = objc_make_node(OBJC_UNARY_MSG_EXPR_NODE);
  SET_SUB(node, unary_msg_expr.recv, recv);
  node->a.unary_msg_expr.sel_name = sel_name;
  node->a.unary_msg_expr.self_is_inst = self_is_inst;

  return node;
}

objc_node_t
objc_make_vsbl_spec_node(int vsbl)
{
  objc_node_t node;

  node = objc_make_node(OBJC_VSBL_SPEC_NODE);
  node->a.ival = vsbl;

  return node;
}
